/**
 * 两种操作:
 * 1 将[s...e]移动到最前
 * 2 将[s...e]移动到最后
 * 最后输出数组
 * HackRank不能提交包含中文的代码, 且不支持ONLINE_JUDGE
 */
#include <bits/stdc++.h>
using namespace std;

using llt = long long;

struct SplayTree{

using llt = int;

using data_type = llt;  
using value_type = llt; 
using lazy_type = llt;  

static int const LEFT = 0;
static int const RIGHT = 1;

struct node_t { // 
    int parent;
    int son[2];
	int size;   // 
	data_type data;   // 
	int flip;         // 
	value_type value; // 
	lazy_type lazy;   // 
};

int Root;
vector<node_t> Nodes; // 
int toUsed;


value_type _up_(const value_type & ls, const value_type & rs) {
	// assert(0);
	return 0;
}


void _dn_(int t, const lazy_type & delta) {
	// assert(0);
}


static value_type mkValue(const data_type & data) {
	// assert(0);
	return 0;
}

static const value_type value_zero() {
	static const value_type VALUE_0 = 0;
	return VALUE_0;
}

static const lazy_type lazy_zero() {
	static const lazy_type LAZY_0 = 0;
	return LAZY_0;
}

static const data_type data_zero() {
	static const data_type DATA_0 = 0;
	return DATA_0;
}


int _sn(int t) {
	assert(t != Root);
	return Nodes[Nodes[t].parent].son[LEFT] == t ? LEFT : RIGHT;
}


void _pushUp(int t) {
	Nodes[t].size = 1;
	Nodes[t].value = mkValue(Nodes[t].data);
    int son = Nodes[t].son[LEFT];
	if(son) {
		Nodes[t].size += Nodes[son].size;
		// Nodes[t].value = _up_(Nodes[son].value, Nodes[t].value);
	}
	son = Nodes[t].son[RIGHT];
	if(son) {
		Nodes[t].size += Nodes[son].size;
		// Nodes[t].value = _up_(Nodes[son].value, Nodes[t].value);
	}
	return;
}


void _pushDown(int t) {
	// int son;
	// if(Nodes[t].flip & 1) {
	// 	swap(Nodes[t].son[LEFT], Nodes[t].son[RIGHT]);
	// 	if(son = Nodes[t].son[LEFT]) Nodes[son].flip ^= 1;
	// 	if(son = Nodes[t].son[RIGHT]) Nodes[son].flip ^= 1;
	// 	Nodes[t].flip ^= 1;
	// }

    // if(Nodes[t].lazy == lazy_zero()) return;
	
	// auto & lz = Nodes[t].lazy;
	// if(son = Nodes[t].son[LEFT]) _dn_(son, lz);
	// if(son = Nodes[t].son[RIGHT]) _dn_(son, lz);

	// lz = lazy_zero();
	return;
}

// 
int _newNode(const data_type & data) {
	auto & n = Nodes[++toUsed];
	assert(toUsed < Nodes.size());
	n.value = mkValue(n.data = data);
	return toUsed;
}

// 
void _link(int parent, int sn, int son) {
    Nodes[Nodes[parent].son[sn] = son].parent = parent;
}

// 
void _rotate(int t) {
    assert(t != Root);
	int p = Nodes[t].parent;
	int sn = _sn(t);
	int osn = sn ^ 1;

	_link(p, sn, Nodes[t].son[osn]);
	if(p != Root) _link(Nodes[p].parent, _sn(p), t);
	else Nodes[t].parent = 0;
	_link(t, osn, p);

	_pushUp(p);
}

//
void _splay(int p, int t) {
    int pp;
	while((pp = Nodes[t].parent) != p) {
		if(Nodes[pp].parent != p) {
			_sn(pp) == _sn(t) ? _rotate(pp) : _rotate(t);
		}
		_rotate(t);
	}
	_pushUp(t); // 
	if(0 == p) Root = t;
	return;
}

// 
int _kth(int t, int k) {
    assert(0 <= k and k < Nodes[t].size);
	_pushDown(t);
	int son = Nodes[t].son[LEFT];
	int s = son ? Nodes[son].size : 0;
	if(k < s) return _kth(son, k);
	return s < k ? _kth(Nodes[t].son[RIGHT], k - s - 1) : t;
}

void _build(int & t, int parent, int sn, int s, int e, const data_type a[]) {
	int mid = (s + e) >> 1;

	t = _newNode(a[mid]); 
	Nodes[t].parent = parent;

	if(s < mid) _build(Nodes[t].son[LEFT], t, LEFT, s, mid - 1, a);
	if(mid < e) _build(Nodes[t].son[RIGHT], t, RIGHT, mid + 1, e, a);

	_pushUp(t);
	return;
}

//
void init(int capa){
	/// 
	Nodes.assign(capa + 3, {0, {0, 0}, 0, data_zero(), 0, value_zero(), lazy_zero()});
	toUsed = 0;
	return;
}


void build(int n, const data_type a[]) {
    _build(Root, 0, 0, 0, n + 1, a);    
	return;
}

void move(int s, int e, int pos) {
	int n = Nodes[Root].size - 2;
	assert(1 <= s and s <= e and e <= n);
	assert(1 <= pos and pos <= n + 1); //
	assert(pos < s or pos > e);

	int t = _kth(Root, s - 1);
	_splay(0, t);

	int tt = _kth(Root, e + 1);
	_splay(Root, tt);

	int son = Nodes[tt].son[LEFT];
	Nodes[tt].son[LEFT] = 0;
    _pushUp(tt); _pushUp(Root);


    t = _kth(Root, pos < s ? pos - 1 : pos - 1 - (e - s + 1));
	_splay(0, t);
 
	tt = _kth(Root, pos < s ? pos : pos - (e - s + 1));
	_splay(Root, tt);

	_link(tt, LEFT, son);
	_pushUp(tt); _pushUp(Root);
	return;
}


void disp(ostream & os) {
	os << "SplayTree " << Root << ":" << endl;
    queue<int> q;
	q.push(Root);
	while(not q.empty()){
		auto h = q.front(); q.pop();
		_pushDown(h);
		auto & n = Nodes[h];
		os << h << ": (" << n.son[LEFT] << ", " << n.son[RIGHT] << ")";
		os << ", size = " << n.size << ", data = " << n.data;
		os << ", info = " << n.value;
		os << endl;
		if(n.son[LEFT]) q.push(n.son[LEFT]);
		if(n.son[RIGHT]) q.push(n.son[RIGHT]);
	}
	return;
}


void dispInOrder(ostream & os) {
    function<void(int)> __dfs = [&, this](int u){
        this->_pushDown(u);
		auto & n = this->Nodes[u];
		int son = n.son[LEFT];
		if(son) __dfs(son);
		os << n.data << " ";
		if(son = n.son[RIGHT]) __dfs(son);
	};

	auto t = _kth(Root, 0);
	_splay(0, t);
	auto tt = _kth(Root, Nodes[Root].size - 1);
	_splay(Root, tt);
	t = Nodes[tt].son[LEFT];
	__dfs(t);
	return;
}

};


SplayTree St;
int N, M;
vector<int> A;

int main(){
#ifndef ONLINE_JUDGE
    // freopen("z.txt", "r", stdin);
#endif
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin >> N >> M;
    A.assign(N + 2, 0);
    for(int i=1;i<=N;++i) cin >> A[i];
	St.init(N);
    St.build(N, A.data());
    // Tree.disp(cout);
    for(int c,a,b,q=1;q<=M;++q){
        cin >> c >> a >> b;
        if(1 == c){
            if(a > 1) St.move(a, b, 1);            
        }else if(2 == c){
            if(b < N) St.move(a, b, N + 1);
        }else{
            assert(0);
        }
        // Tree.disp(cout);
    }

    auto a1 = St.Nodes[St._kth(St.Root, 1)].data;
    auto an = St.Nodes[St._kth(St.Root, N)].data;
    auto ans = a1 - an;
    if(ans < 0) ans = -ans;
    cout << ans << endl;

    St.dispInOrder(cout);
	cout << endl;
    return 0;
}